import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
import matplotlib.patches as patches
import os
from matplotlib.colors import LinearSegmentedColormap
from datetime import datetime

# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号

# 定义常量 - 保存结果的目录
RESULTS_DIR = r"D:\大三上\大数据分析及数据可视化\《Excel数据可视化 - 从图表到数据大屏》-清华-郭宏远\实验\results"


def load_erp_data():
    """加载ERP订单数据"""
    # 定义可能的文件路径
    possible_paths = [
        r"D:\大三上\大数据分析及数据可视化\《Excel数据可视化 - 从图表到数据大屏》-清华-郭宏远\实验\data\erp_order_data.xlsx",
        r"D:\大三上\大数据分析及数据可视化\《Excel数据可视化 - 从图表到数据大屏》-清华-郭宏远\实验\erp_order_data.xlsx"
    ]

    for path in possible_paths:
        if os.path.exists(path):
            try:
                df = pd.read_excel(path)
                # 确保日期格式正确
                if 'order_time' in df.columns:
                    df['order_time'] = pd.to_datetime(df['order_time'])
                print(f"✓ 数据加载成功: {path}")
                return df
            except Exception as e:
                print(f"读取 {path} 失败: {e}")
                continue

    raise FileNotFoundError("未找到erp_order_data.xlsx文件，请确认文件是否存在或路径是否正确")


def process_region_data(df):
    """处理区域数据，对比2024年和2025年同期销量"""
    # 确保order_time是datetime类型
    if 'order_time' not in df.columns:
        raise ValueError("数据中缺少'order_time'列，无法进行时间分析")

    # 确保province列存在
    if 'province' not in df.columns:
        raise ValueError("数据中缺少'province'列，无法进行区域分析")

    # 确保product_amount列存在
    if 'product_amount' not in df.columns:
        raise ValueError("数据中缺少'product_amount'列，无法计算销售金额")

    # 创建副本防止修改原始数据
    df = df.copy()

    # 提取年份和月份
    df['year'] = df['order_time'].dt.year
    df['month'] = df['order_time'].dt.month

    # 获取数据中的年份
    years = df['year'].unique()
    years = sorted(years)

    if len(years) < 2:
        raise ValueError("数据中年份不足，需要至少两年的数据进行对比")

    # 选择最近的两个完整年份
    year1 = years[-2]  # 倒数第二年
    year2 = years[-1]  # 最新年份

    # 确定统计截止日期
    latest_date = df['order_time'].max()

    # 确定时间范围
    if latest_date.year == year2:
        # 如果当前年份是最新年份，使用最近6个月
        start_date = latest_date - pd.DateOffset(months=5)
        # 仅使用数据中实际存在的月份
        month_range = range(start_date.month, latest_date.month + 1)

        # 2025年数据（当前年）
        data_year2 = df[(df['year'] == year2) & (df['month'].isin(month_range))]
        # 2024年同期数据
        data_year1 = df[(df['year'] == year1) & (df['month'].isin(month_range))]

        # 为标题准备时间描述
        time_desc = f"{start_date.month}月-{latest_date.month}月"
    else:
        # 如果数据中没有当前年份的完整数据，使用完整年份
        data_year2 = df[df['year'] == year2]
        data_year1 = df[df['year'] == year1]
        time_desc = "全年"

    print(f"使用 {year1}年 对比 {year2}年{time_desc}的数据")
    print(f"{year1}年记录数: {len(data_year1)}")
    print(f"{year2}年{time_desc}记录数: {len(data_year2)}")

    # 按地区汇总销量
    regions_year1 = data_year1.groupby('province')['product_amount'].sum().reset_index()
    regions_year2 = data_year2.groupby('province')['product_amount'].sum().reset_index()

    # 重命名列
    regions_year1.columns = ['province', f'sales_{year1}']
    regions_year2.columns = ['province', f'sales_{year2}']

    # 合并两个数据集
    merged = pd.merge(regions_year1, regions_year2, on='province', how='inner')

    # 计算同比增长率
    merged[f'growth_rate'] = ((merged[f'sales_{year2}'] - merged[f'sales_{year1}']) / merged[f'sales_{year1}']) * 100

    # 只保留主要地区（华南、华北、东北、西北、华东）
    main_regions = ['华南', '华北', '东北', '西北', '华东', '北京市', '上海市', '广东省', '江苏省', '浙江省', '四川省',
                    '湖北省', '陕西省']
    available_regions = [r for r in main_regions if r in merged['province'].values]

    if not available_regions:
        # 如果主要地区都没有，使用数据中存在的所有地区
        print("警告：数据中没有包含主要地区。将使用所有可用地区。")
        available_regions = merged['province'].tolist()

    merged = merged[merged['province'].isin(available_regions)]

    # 按2025年销售量排序（从高到低）
    merged = merged.sort_values(f'sales_{year2}', ascending=False)

    # 重命名列以便后续处理
    merged = merged.rename(columns={
        f'sales_{year1}': 'sales_last',
        f'sales_{year2}': 'sales_current',
        f'growth_rate': 'growth_rate'
    })

    # 存储年份信息
    merged.attrs['year1'] = year1
    merged.attrs['year2'] = year2
    merged.attrs['time_desc'] = time_desc

    return merged


def create_region_comparison_chart():
    """创建区域销量对比图表"""
    # 加载数据
    df = load_erp_data()

    # 处理区域数据
    region_data = process_region_data(df)

    # 提取数据
    regions = region_data['province'].tolist()
    sales_last = region_data['sales_last'].tolist()
    sales_current = region_data['sales_current'].tolist()
    growth_rates = region_data['growth_rate'].tolist()

    # 获取年份信息
    year1 = region_data.attrs['year1']
    year2 = region_data.attrs['year2']
    time_desc = region_data.attrs['time_desc']

    # 检查数据有效性
    if not regions:
        print("错误：没有找到有效的区域数据。")
        return None, None

    # 创建渐变颜色映射
    blue_colors = ['#16213E', '#0F3460', '#1A5F7A', '#2C8C99', '#4BB5C2', '#7FD6E3']
    red_colors = ['#5C1E2B', '#8A2D3D', '#B73E4F', '#D54D5F', '#E56A72', '#F08B8F']

    # 创建颜色映射
    blue_cmap = LinearSegmentedColormap.from_list('blue', blue_colors, N=100)
    red_cmap = LinearSegmentedColormap.from_list('red', red_colors, N=100)

    # 创建图形 - 靛蓝色背景
    fig = plt.figure(figsize=(14, 9), facecolor='#1A1A2E')
    ax = fig.add_subplot(111, facecolor='#1A1A2E')

    # 设置y轴位置
    y_pos = np.arange(len(regions))

    # 设置条形高度
    bar_height = 0.5

    # 计算最大值以调整x轴范围
    max_sales = max(max(sales_last), max(sales_current))

    # 创建图表
    for i, (y, sale_last, sale_current, growth_rate) in enumerate(zip(y_pos, sales_last, sales_current, growth_rates)):
        # 2024年销量（左侧深蓝色）
        if sale_last > 0:
            gradient_width = 80
            for j in range(gradient_width):
                width_segment = sale_last / gradient_width
                x_left = j * width_segment
                color = blue_cmap(1 - (j / gradient_width) * 0.7)
                rect = patches.Rectangle(
                    (x_left, y - bar_height / 2), width_segment, bar_height,
                    linewidth=0, facecolor=color, alpha=0.9
                )
                ax.add_patch(rect)

            # 添加2024年数据标签
            ax.text(sale_last * 0.5, y, f'{int(sale_last)}',
                    ha='center', va='center', fontsize=12, fontweight='bold', color='#FFFFFF',
                    bbox=dict(boxstyle='round,pad=0.2', facecolor='#2C3E50', edgecolor='none', alpha=0.7))

        # 2025年销量（中间浅蓝色）
        if sale_current > 0:
            # 计算2025年条形的起点（在2024年条形右侧）
            start_x = sale_last if sale_last > 0 else 0

            # 创建渐变效果
            gradient_width = 80
            for j in range(gradient_width):
                width_segment = sale_current / gradient_width
                x_left = start_x + j * width_segment
                color = blue_cmap(1 - (j / gradient_width) * 0.3)  # 更浅的蓝色
                rect = patches.Rectangle(
                    (x_left, y - bar_height / 2), width_segment, bar_height,
                    linewidth=0, facecolor=color, alpha=0.9
                )
                ax.add_patch(rect)

            # 添加2025年数据标签
            ax.text(start_x + sale_current * 0.5, y, f'{int(sale_current)}',
                    ha='center', va='center', fontsize=12, fontweight='bold', color='#FFFFFF',
                    bbox=dict(boxstyle='round,pad=0.2', facecolor='#2C3E50', edgecolor='none', alpha=0.7))

        # 同比变化率（右侧红色）
        if growth_rate < 0:  # 只处理下降的情况，与示例一致
            # 红色部分的宽度基于同比变化率
            red_width = max_sales * 0.15  # 固定宽度以保持一致性

            # 创建渐变红色
            gradient_width = 80
            for j in range(gradient_width):
                width_segment = red_width / gradient_width
                x_left = start_x + sale_current + j * width_segment
                color = red_cmap(1 - (j / gradient_width) * 0.7)
                rect = patches.Rectangle(
                    (x_left, y - bar_height / 2), width_segment, bar_height,
                    linewidth=0, facecolor=color, alpha=0.9
                )
                ax.add_patch(rect)

            # 添加同比变化率标签
            ax.text(start_x + sale_current + red_width * 0.5, y, f'{growth_rate:.1f}%',
                    ha='center', va='center', fontsize=12, fontweight='bold', color='#FFFFFF',
                    bbox=dict(boxstyle='round,pad=0.2', facecolor='#5C1E2B', edgecolor='none', alpha=0.7))

    # 设置坐标轴
    ax.set_yticks(y_pos)
    ax.set_yticklabels(regions, fontsize=14, fontweight='bold', color='#E0E0E0')
    ax.tick_params(axis='x', labelsize=14, colors='#E0E0E0')
    ax.set_xticks([])

    # 设置标题
    title_main = f'{year2}年{time_desc}各区域销量及同比情况'

    # 分析最近的趋势
    num_declining = sum(1 for rate in growth_rates if rate < 0)

    # 找出下降最多的区域
    if num_declining > 0:
        max_decline_idx = np.argmin(growth_rates)
        max_decline_region = regions[max_decline_idx]
        max_decline_rate = growth_rates[max_decline_idx]

        # 生成副标题
        subtitle = f'各区域商品销量同比{year1}年均有下降，其中{max_decline_region}下降最多，同比下降{abs(max_decline_rate):.1f}%'
    else:
        subtitle = f'各区域商品销量同比{year1}年均有增长，其中{regions[0]}增长最快，同比增长{max(growth_rates):.1f}%'

    # 设置标题并调整位置以避免重叠
    ax.set_title(f'{title_main}\n{subtitle}',
                 fontsize=20, fontweight='bold',
                 pad=35,  # 增加标题与图表之间的间距
                 y=1.05,  # 将标题向上移动
                 color='#FFFFFF')

    # 美化坐标轴
    for spine in ax.spines.values():
        spine.set_color('#4A4A6A')
        spine.set_linewidth(2)

    # 设置网格线
    ax.grid(axis='x', alpha=0.3, linestyle='--', color='#4A4A6A')
    ax.set_axisbelow(True)

    # 设置x轴范围
    max_value = max(sales_current) * 1.5 if max(sales_current) > 0 else 100
    ax.set_xlim(0, max_value)

    # 添加数据来源
    latest_date = df['order_time'].max()
    latest_date_str = latest_date.strftime('%Y.%m.%d')
    source_text = f'*注：数据来源于公司销售系统，统计日期截至{latest_date_str}'
    ax.text(0.02, 0.02, source_text, transform=ax.transAxes,
            fontsize=10, color='#B0B0B0', alpha=0.7, va='bottom')

    # 调整布局
    plt.tight_layout()

    # 确保结果目录存在
    os.makedirs(RESULTS_DIR, exist_ok=True)
    # 保存图片
    output_path = os.path.join(RESULTS_DIR, '07_区域对比图.png')
    plt.savefig(output_path, dpi=300, bbox_inches='tight',
                facecolor='#1A1A2E', edgecolor='none')

    plt.show()

    # 数据分析
    print("\n区域销量对比图数据分析：")
    print(f"- 数据覆盖区域：{len(regions)}个地区")
    print(f"- {year2}年{time_desc}总销量：{sum(sales_current):.2f}万元")
    print(f"- {year1}年同期总销量：{sum(sales_last):.2f}万元")

    if num_declining > 0:
        print(f"- 销量下降的区域：{num_declining}个（全部区域均下降）")
        print(f"- 最大下降幅度：{abs(max_decline_rate):.1f}%（{max_decline_region}）")
    else:
        print(f"- 销量增长的区域：{len(regions)}个（全部区域均增长）")
        print(f"- 最大增长幅度：{max(growth_rates):.1f}%（{regions[0]}）")

    return fig, ax


# 执行代码
if __name__ == "__main__":
    try:
        fig, ax = create_region_comparison_chart()
    except Exception as e:
        print(f"图表生成失败: {e}")
        raise